package cn.itrip.auth.service.toKen;

import cn.itrip.beans.pojo.ItripUser;
import cn.itrip.common.MD5;
import cn.itrip.common.RedisAPI;
import cn.itrip.common.UserAgentUtil;
import com.alibaba.fastjson.JSON;
import cz.mallat.uasparser.UserAgentInfo;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

@Service
public class TokenServiceImpl implements TokenService {

    @Resource
    private RedisAPI redisAPI;
    private int expire = SESSION_TIMEOUT;//2h
    private  String toKenPrefix = "toKen:";//统一加入token前缀

    public int getExpire() {
        return expire;
    }
    public void setExpire(int expire) {
        this.expire = expire;
    }
    @Override
    public String generateToken(String agent, ItripUser user) {
        try{
            //通过头去判断客户端
            UserAgentInfo userAgentInfo = UserAgentUtil.getUasParser().parse(agent);
            StringBuilder builder = new StringBuilder();
            builder.append(toKenPrefix); //统一前缀
            //判断设备然后拼接
            if(userAgentInfo.getDeviceType().equals(UserAgentInfo.UNKNOWN)){
                if(UserAgentUtil.CheckAgent(agent)){
                    builder.append("MOBILE-");
                }else{
                    builder.append("PC-");
                }
            }else if(userAgentInfo.getDeviceType().equals("Personal computer")){
                builder.append("PC-");
            }else {
                builder.append("MOBILE-");
            }
            builder.append(MD5.getMd5(user.getUserCode(),32)+"-");//加密用户名称
            builder.append(user.getId()+"-");
            builder.append(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())+"-");
            builder.append(MD5.getMd5(agent,6));//识别客户端的简化实现
            return builder.toString();
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void save(String token, ItripUser user) {
        if(token.startsWith(toKenPrefix+"PC-")){
            redisAPI.set(token,expire, JSON.toJSONString(user));
        }else{
            //手机认证信息永不失效
            redisAPI.set(token,JSON.toJSONString(user));
        }
    }

    @Override
    public String replaceToken(String agent, String token) throws Exception {
        //验证旧token是否有效
        if(!exists(token)){
            throw new Exception("未知的token或token已过期");
        }
        Date TokenGenTime;//token生成时间
        try{
            String[] tokenDetails = token.split("-");
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
            TokenGenTime = format.parse(tokenDetails[3]);
        }catch (Exception e){
            e.printStackTrace();
            throw new Exception("token格式错误:"+token);
        }
        //token已产生时间
        long passed = Calendar.getInstance().getTimeInMillis()-TokenGenTime.getTime();
        if(passed<REPLACEMENT_PROTECTION_TIMEOUT*1000){
            throw new Exception("token处于置换保护期内，剩余:"+(REPLACEMENT_PROTECTION_TIMEOUT*1000-passed)/1000+"(S)禁止置换");
        }
        String newToken = "";
        ItripUser user = this.load(token);
        long ttl = redisAPI.ttl(token);
        if(ttl>0 || ttl==-1){//兼容手机和PC端的token在有效期
            newToken = this.generateToken(agent,user);
            this.save(newToken,user);//缓存新token
            //2分钟后旧token失效
            redisAPI.set(token,REPLACEMENT_DELAY,JSON.toJSONString(user));
        }
        return newToken;
    }

    @Override
    public void delete(String token) {
        if(redisAPI.exist(token)){
            redisAPI.del(token);
        }
    }

    @Override
    public ItripUser load(String token) {
        return JSON.parseObject(redisAPI.get(token),ItripUser.class);
    }

    @Override
    public boolean exists(String token) {
        return redisAPI.exist(token);
    }

    @Override
    public boolean validate(String agent, String token){
        if(!redisAPI.exist(token)){
            return false;
        }
        String agentMD5 = token.split("-")[4];
        if(!MD5.getMd5(agent,6).equals(agentMD5)){
            return false;
        }
        return true;
    }
}
